The following article is from Jacen的技术笔记Author Jacen
来源:Jacen的技术笔记作者:Jacen
对于想要入门C++的同学来说,《C++ Primer》是一本不能错过的入门书籍,它用平易近人的实例化教学激发学生的学习兴趣,帮助学生一步步走进C++的大门。在本文中,作者Jacen用两万多字总结了《C++ Primer 中文版(第五版)》1-16章的阅读要点,可以作为该书的阅读参考。注:原书更为详细,本文仅作学习交流使用。
迭代器运算符*iter // 解引用,返回引用 iter->mem // 等价于 (*iter).mem ++iter --iter iter1 == iter2 iter1 != iter2 iter + n iter - n iter += n iter -= n iter1 - iter2 // 两个迭代器相减的结果是它们之间的距离 >, >=, <, <= // 位置比较::: warning凡是使用了迭代器的循环体,都不能向迭代器所属的容器添加元素。:::
Sales_data add(const Sales_data &lhs, const Sales_data &rhs) { Sales_data sum = lhs; // copy data members from lhs into sum sum.combine(rhs); // add data members from rhs into sum return sum; }
// transactions contain ISBN, number of copies sold, and sales price istream& read(istream &is, Sales_data &item) { double price = 0; is >> item.bookNo >> item.units_sold >> price; item.revenue = price * item.units_sold; return is; }
// will hold a line and word from input, respectively string line, word;
// will hold all the records from the input vector<PersonInfo> people;
// read the input a line at a time until end-of-file (or other error) while (getline(is, line)) { PersonInfo info; // object to hold this record's data istringstream record(line); // bind record to the line we just read record >> info.name; // read the name while (record >> word) // read the phone numbers info.phones.push_back(word); // and store them people.push_back(info); // append this record to people } // for each entry in people for (vector<PersonInfo>::const_iterator entry = people.begin(); entry != people.end(); ++entry) { ostringstream formatted, badNums; // objects created on each loop
// for each number for (vector<string>::const_iterator nums = entry->phones.begin(); nums != entry->phones.end(); ++nums) { if (!valid(*nums)) { badNums << " " << *nums; // string in badNums } else // ``writes'' to formatted's string formatted << " " << format(*nums); } if (badNums.str().empty()) // there were no bad numbers os << entry->name << " " // print the name << formatted.str() << endl; // and reformatted numbers else // otherwise, print the name and bad numbers cerr << "input error: " << entry->name << " invalid number(s) " << badNums.str() << endl; } 第九章 顺序容器 P292-P332顺序容器为程序员提供了控制元素存储和访问顺序的能力。
9.1 顺序容器概述
类型
作用
vector
可变数组大小。支持快速随机访问。在尾部之外的位置插入或删除元素可能很慢。
deque
双端队列。支持快速随机访问。在头尾位置插入/删除速度很快。
list
双向链表。只支持双向顺序访问。在list中任何位置进行插入/删除操作速度都很快。
forward_list
单向链表。只支持单向顺序访问。在链表任何位置进行插入/删除操作速度都很快。
array
固定大小数组。支持快速随机访问。不能添加或删除元素。
string
与vector相似的容器,但专门用于保存字符、随机访问快。在尾部插入/删除速度快。
9.2 容器库概述
一般,每个容器都定义在一个头文件中。容器均定义为模板类。
类型别名
iterator
此容器类型的迭代器类型
const_iterator
可以读取元素,但不能修改元素的迭代器类型
size_type
无符号整数类型,足够保存此种容器类型最大可能容器的大小
difference_type
带符号整数类型,足够保存两个迭代器之间的距离
value_type
元素类型
reference
元素的左值诶性:与value_type&含义相同
const_reference
元素的const左值类型(即,const value_type&)
构造函数
C c;
默认构造函数,构造空容器
C c1(c2)
构造c2的拷贝c1
C c(b, e)
构造c,将迭代器b和e指定的范围内的元素拷贝到c(array不支持)
C c{a, b, c...}
列表初始化c
赋值与swap
c1=c2
将c1中的元素替换为c2中元素
c1 = {a, b, c...}
将c1中的元素替换为列表中元素(不适用于array)
a.swap(b)
交换a和b的元素
swap(a, b)
与a.swap(b)等价
大小
c.size()
c中元素的数组(不支持forward_list)
c.max_size()
c中可保存的最大元素数目
c.empty()
若c中存储了元素,返回false,否则返回true
添加/删除元素(不适用于array)
c.insert(args)
将args中的元素拷贝进c
c.emplace(inits)
使用inits构造c中的一个元素
c.erase(args)
删除args指定的元素
c.clear()
删除c中的所有元素,返回void
关系运算符
==, !=
所有容器都支持相等(不等运算符)
<,<=,>,>=
关系运算符(无序关联容器不支持)
获取迭代器
c.begin(), c.end()
返回指向c的首元素和尾元素之后位置的迭代器
c.cbengin(),c.cend()
返回const_iterator
反向容器的额外成员(不支持forward_list)
reverse_iterator
按逆序寻址元素的迭代器
const_reverse_iterator
不能修改元素的逆序迭代器
c.rbegin(), c.rend()
返回指向c的尾元素和首元素之前位置的迭代器
c.crbegin(), c.crend()
返回const_reverse_iterator
(1)迭代器标准库的迭代器允许我们访问容器中的元素,所有迭代器都是通过解引用运算符来实现这个操作。一个迭代器返回由一对迭代器表示,两个迭代器分别指向同一个容器中的元素或者是尾元素之后的位置。它们标记了容器中元素的一个范围。左闭合区间:[begin, end)while (begin !=end){ *begin = val; ++begin; }(2)容器类型成员见概述通过别名,可以在不了解容器中元素类型的情况下使用它。(3)begin和end成员begin是容器中第一个元素的迭代器end是容器尾元素之后位置的迭代器(4)容器定义和初始化P290C c; // 默认构造函数 C c1(c2) C c1=c2 C c{a,b,c...} // 列表初始化 C c={a,b,c...} C c(b,e) // c初始化为迭代器b和e指定范围中的元素的拷贝 // 只有顺序容器(不包括array)的构造函数才能接受大小参数 C seq(n) C seq(n,t)将一个容器初始化为另一个容器的拷贝:当将一个容器初始化为另一个容器的拷贝时,两个容器的容器类型和元素类型都必须相同。不过,当传递迭代器参数来拷贝一个范围时,就不要求容器类型相同,只要能将要拷贝的元素转换为要初始化的容器的元素类型即可。标注库array具有固定大小:不能对内置数组类型进行拷贝或对象赋值操作,但array并无此限制。P301(5)赋值与swaparrray类型不允许用花括号包围的值列表进行赋值。array<int, 10> a2={0}; //所有元素均为0 s2={0}; // 错误!seq.assign(b,e) // 将seq中的元素替换为迭代器b和e所表示的范围中的元素。迭代器b和e不能指向seq中的元素。swap用于交换2个相同类型容器的内容。调用swap之后,两个容器中的元素将交换。(6)容器大小操作size 返回容器中元素的数目empty 当size为0返回布尔值true,否则返回falsemax_size 返回一个大于或等于该类型容器所能容纳的最大元素数的值(7)关系运算符关系运算符左右两边的元素符对象必须是相同类型的容器。::: tip只有当元素类型也定义了相应的比较运算符,才可以使用关系元素安抚来比较两个容器:::
(1)shared_ptr类shared_ptr<string> p1;make_shared函数:make_shared在动态内存中分配一个对象并初始化它,返回此对象的shared_ptr。share_ptr<int> p3 = make_shared<int>(42);shared_ptr的拷贝和赋值:每个shared_ptr都有一个关联的计数器,称为引用计数。一旦一个shared_ptr的引用计数变为0,就会自动释放自己所管理的对象。(2)直接管理内存运算符new分配分配内存,delete释放new分配的内存。使用new动态分配和初始化对象:// 默认情况下,动态分配的对象是默认初始化的 int *pi = new int; // pi指向一个动态分配的、未初始化的无名对象// 直接初始化方式 int *pi = new int(1024); // pi指向的对象的值为1024// 对动态分配的对象进行值初始化,只需在类型名之后加上一对空括号 int *pi1 = new int; // 默认值初始化;*pi1的值未定义 int *pi2 = new int(); // 值初始化为0;*pi2为0动态分配的const对象:const int *pci = new const int(1024);释放动态内存:delete p;delete表达式执行两个动作:销毁给定的指针指向的对象;释放对应的内存。(3)unique_ptr某个时刻,只能有一个unique_ptr指向一个给定对象。当unique_ptr销毁时,它所指向的对象也被销毁。
new : 从自由空间分配内存。new T 分配并构造一个类型为T的指针。如果T是一个数组类型,new 返回一个指向数组首元素的指针。类似的,new [n] T 分配 n 个类型为T的对象,并返回指向数组首元素的指针。空悬指针:一个指针,指向曾经保存一个对象但现在已释放的内存。智能指针:标准库类型。负责在恰当的时候释放内存。 第十三章 拷贝控制 P440-P486五种拷贝控制操作:拷贝构造函数、拷贝赋值运算符、移动构造函数、移动赋值运算符、析构函数。拷贝构造函数、移动构造函数定义了当用同类型的另一个对象初始化本对象时做什么。拷贝赋值运算符、移动赋值运算符定义了将一个对象赋予同类型的另一个对象时做什么。析构函数定义了当此类型对象销毁时做什么。
受保护的成员:派生类的成员和友元只能访问派生类对象中的基类部分的受保护成员;对于普通的基类对象中的成员不具有特殊的访问权限。P543公有、私有和受保护继承:派生访问说明符对于派生类的成员(及友元)能否访问其直接基类的成员无影响;对基类成员的访问权限只与基类中的访问说明符有关。派生访问说明符的目的是控制派生类用户对于基类成员的访问权限。改变个别成员的可访问性:通过在类的内部使用using声明语句,我们可以将该类的直接或间接基类中的任何可访问成员标记出来。class Derived : private Base { public: using Base::size; }::: tip派生类只能为它可访问的名字提供using声明。:::默认的继承保护级别:使用class关键字定义的派生类是私有继承的;使用struct关键字定义的派生类是共有继承的。class Base {}; struct D1 : Base {}; // 默认public继承 class D2 : Base {}; // 默认private继承